/*
 * st7066u.c
 *
 *  Created on: Sep 13, 2013
 *      Author: Ken Arok
 */

#include "config_board.h"

#if BOARD_2_1_USED

#if 1

#include "board.h"
#include "gpio.h"
#include "delay.h"
#include "st7066u.h"

/** \brief Delay some cycle for LCD setup and hold waveform timing.
 *
 * \param _val	Value of delay cycle.
 *
 */
static void _delay_cycles(uint16_t _val)
{
	uint16_t _dummy;

	for(_dummy = 0; _dummy < _val; _dummy++);
}

/* --------------------------------------------------------------------------------- */

void st7066u_send_data(const uint8_t _data)
{
	uint8_t _mask, _val;

	gpio_set_pin_low(LCD_RW_GPIO);
	gpio_set_pin_high(LCD_RS_GPIO);

	/* Setup Data upper 4-bit. */
	_mask = gpio_read_port(LCD_PORT);
	_mask = _mask & 0x0F;
	_val = (_data & 0xF0) | _mask;
	gpio_write_port(LCD_PORT, _val);

	/* Sampling high to low. */
	gpio_set_pin_high(LCD_E_GPIO);
	_delay_cycles(7);
	gpio_set_pin_low(LCD_E_GPIO);
	_delay_cycles(2);

	/* Setup Write lower 4-bit. */
	_mask = gpio_read_port(LCD_PORT);
	_mask = _mask & 0x0F;
	_val = (_data & 0x0F) << 4;
	_val = _val | _mask;
	gpio_write_port(LCD_PORT, _val);

	/* Sampling. */
	_delay_cycles(2);
	gpio_set_pin_high(LCD_E_GPIO);
	_delay_cycles(7);
	gpio_set_pin_low(LCD_E_GPIO);
	delay_us(120);
}


void st7066u_send_instruction(const uint8_t _instr)
{
	uint8_t _mask, _val;

	gpio_set_pin_low(LCD_RW_GPIO);
	gpio_set_pin_low(LCD_RS_GPIO);

	/* Setup Data upper 4-bit. */
	_mask = gpio_read_port(LCD_PORT);
	_mask = _mask & 0x0F;
	_val = (_instr & 0xF0) | _mask;
	gpio_write_port(LCD_PORT, _val);

	/* Sampling high to low. */
	gpio_set_pin_high(LCD_E_GPIO);
	_delay_cycles(7);
	gpio_set_pin_low(LCD_E_GPIO);
	_delay_cycles(2);

	/* Setup Write lower 4-bit. */
	_mask = gpio_read_port(LCD_PORT);
	_mask = _mask & 0x0F;
	_val = (_instr & 0x0F) << 4;
	_val = _val | _mask;
	gpio_write_port(LCD_PORT, _val);

	/* Sampling. */
	_delay_cycles(5);
	gpio_set_pin_high(LCD_E_GPIO);
	_delay_cycles(7);
	gpio_set_pin_low(LCD_E_GPIO);
	delay_us(500);
}

void st7066u_init(void)
{
	const uint8_t txdata[5] = {0x30, 0x28, 0x0C, 0x01, 0x06};

	/* Configure I/O port. */
	gpio_configure_output(LCD_BLON_GPIO);
	gpio_configure_output(LCD_RW_GPIO);
	gpio_configure_output(LCD_RS_GPIO);
	gpio_configure_output(LCD_E_GPIO);
	gpio_configure_output(LCD_D7_GPIO);
	gpio_configure_output(LCD_D6_GPIO);
	gpio_configure_output(LCD_D5_GPIO);
	gpio_configure_output(LCD_D4_GPIO);

	/*! Delay >40ms */
	delay_ms(50);

	/*! Function set initial. */
	st7066u_send_instruction(txdata[0]);
	/*! Wait >37us */
	delay_us(40);
	/*! Function set: 8-bit; 2 lines; 5 x 7 dot */
	st7066u_send_instruction(txdata[1]);
	/*! Wait >37us */
	delay_us(40);
	st7066u_send_instruction(txdata[1]);
	/*! Wait >37us */
	delay_us(40);
	/*! Display ON */
	st7066u_send_instruction(txdata[2]);
	/*! Delay >37us */
	delay_us(40);
	/*! Display Clear */
	st7066u_send_instruction(txdata[3]);
	/*! Delay >1.52ms */
	delay_ms(2);
	/*! Entry Mode set: Increment, don't shift */
	st7066u_send_instruction(txdata[4]);

	/* Turn Back light On */
	gpio_set_pin_low(LCD_BLON_GPIO);
}

#endif

#endif /* BOARD_2_1_USED */
